#ifndef __SELECT_SVR_H_
#define __SELECT_SvR_H
#include <iostream>
#include <cassert>
#include <string>
#include <poll.h>
#include "log.hpp"
#include "Sock.hpp"
using std::cout;
using std::endl;

#define FD_NONE -1
class PollServer
{
    static const nfds_t nfds = 2;
public:
    PollServer(const uint16_t &port = 8080)
        : _port(port)
        ,_nfds(nfds)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        logMessage(DEBUG, "create base socket success");

        _fds = new struct pollfd[_nfds];

        for(nfds_t i = 0; i < _nfds; i++)//初始化
        {
            _fds[i].fd = FD_NONE;
            _fds[i].events = _fds[i].revents = 0; 
        }
        _fds[0].fd = _listensock;
        _fds[0].events = POLL_IN;
        _timeout = 1000;
    }

    void start()
    {
        while (true)
        {
            int n = poll(_fds,_nfds,_timeout);

            if (n == 0)
            {
                logMessage(DEBUG, "%s", "time out....");
            }
            else if (n == -1)
            {
                logMessage(WARNING, "select error: %d : %s,", errno, strerror(errno));
            }
            else
            {
                logMessage(DEBUG, "get a new link event..."); 
                // 会一直提醒你取走连接
                // 成功
                HandEvent();
            }
        }
    }

    ~PollServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if(_fds)
            delete []_fds; 
    }

private:
    void Accepter()
    {
        std::string clientIP;
        uint16_t clientPort = 0;

        // 上面读事件已经就绪，可以获取新连接了
        int sock = Sock::Accept(_listensock, &clientIP, &clientPort); // 这里进行accept不会阻塞了
        if (sock < 0)
        {
            logMessage(WARNING, "Accept error");
            return;
        }
        logMessage(DEBUG, "get a new line success : [%s:%d] : %d", clientIP.c_str(), clientPort, _listensock);

        nfds_t pos = 1; // 由于有约定所以我们下标从1开始
        for (; pos < _nfds; pos++)
        {
            if (_fds[pos].fd == FD_NONE)
                break;
        }

        if (pos == _nfds)
        {
            //扩容
            nfds_t newnfds = _nfds * 2;

            struct pollfd* _newfds;
            _newfds = new struct pollfd[newnfds];
            for(int i = 0; i < newnfds; i++)
            {
                if(i < _nfds)
                {
                    _newfds[i].fd = _fds[i].fd;
                    _newfds[i].events = _fds[i].events;
                    _newfds[i].revents = _fds[i].revents;
                }
                else
                {
                    _newfds[i].fd = FD_NONE;
                    _newfds[i].events = _newfds[i].revents = 0;
                }
            }
            _newfds[pos].fd = sock;
            _newfds[pos].events = POLL_IN;
            _nfds = newnfds;
            delete []_fds; 
            _fds = _newfds;
            logMessage(WARNING, "capacity success : sock:%d, _nfds:%ld", sock,_nfds);
        }
        else
        {
            _fds[pos].fd = sock;
            _fds[pos].events = POLL_IN;
        }
    }

    void Recver(int pos)
    {
        // 读事件就绪，input事件到来recv/read
        logMessage(DEBUG, "message in, get IO event: %d",  _fds[pos].fd);
        // 这样读取有bug吗？有的，你怎么保证以读到了一个完整包文呢？
        char buffer[1024];
        int n = recv( _fds[pos].fd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            logMessage(DEBUG, "client[%d]# %s",  _fds[pos].fd, buffer);
        }
        else if (n == 0)
        {
            logMessage(DEBUG, "client[%d] quit, me too...", _fds[pos].fd);
            // 1. 我们也要关闭不需要的fd
            close( _fds[pos].fd);
            // 2. 不要让select帮我关心当前的fd了
             _fds[pos].fd = FD_NONE;
             _fds[pos].events = 0;
        }
        else
        {
            logMessage(WARNING, "%d sock recv error, %d : %s", _fds[pos].fd, errno, strerror(errno));
            // 1. 我们也要关闭不需要的fd
            close(_fds[pos].fd);
            // 2. 不要让select帮我关心当前的fd了
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = 0;
        }
    }

    void HandEvent() 
    {
        for (nfds_t i = 0; i < _nfds; i++)
        {
            // 1.去掉不合法的fd
            if (_fds[i].fd == FD_NONE)
                continue;
            // 2.合法的就一定就绪了？不一定
            if (_fds[i].revents & POLL_IN)
            {
                if (_fds[i].fd == _listensock) Accepter();
                else Recver(i);
            }
        }
    }

    void DebugPrint()
    {
        cout << "_fd_array[]: ";
        for (nfds_t i = 0; i < _nfds; i++)
        {
            if (_fds[i].fd != FD_NONE)
            {
                cout << _fds[i].fd << " ";
            }
        }
        cout << endl;
    }

private:
    uint16_t _port;
    int _listensock;
    struct pollfd* _fds;
    nfds_t _nfds;//程序员认可的链接数
    int _timeout;
};

#endif